#include "ibp_util.h"
#include "ibma_api.h"

char		*g_ibp_ibma_api_kernel_version = IBP_VERSION ;

struct IndexSpace
{
	struct ShareMemory		shm ;
	
	struct IndexSpaceAttaching	*index_space_attaching ;
} ;

struct ConfigSpace
{
	struct ShareMemory		shm ;
	
	struct ConfigSpaceAttaching	*config_space_attaching ;
	struct ConfigSpaceAddresses	config_space_addresses ;
	
	struct list_head		this_node ;
} ;

struct IbmaConfigSpace
{
	char			ibma_conf_pathfilename[ IBP_MAXLEN_FILENAME + 1 ] ;
	
	struct NetAddress	netaddr ;
	struct HttpEnv		*http ;
	
	struct IndexSpace	index_space ;
	struct ConfigSpace	config_space ;
} ;

struct IbmaConfigSpace *IBMAOpenConfigSpace( char *ibma_conf_filename )
{
	struct IbmaConfigSpace	*ibma_config_space = NULL ;
	int			open_config_space_error_flag ;
	
	ibma_config_space = (struct IbmaConfigSpace *)malloc( sizeof(struct IbmaConfigSpace) ) ;
	if( ibma_config_space == NULL )
	{
		ERRORLOGSG( "malloc failed , errno[%d]" , errno );
		return NULL;
	}
	memset( ibma_config_space , 0x00 , sizeof(struct IbmaConfigSpace) );
	
	if( ibma_conf_filename == NULL )
		ibma_conf_filename = "ibma.conf" ;
	snprintf( ibma_config_space->ibma_conf_pathfilename , sizeof(ibma_config_space->ibma_conf_pathfilename)-1 , "%s/etc/%s" , getenv("HOME") , ibma_conf_filename );
	
	ibma_config_space->index_space.shm.shmkey = ftok( ibma_config_space->ibma_conf_pathfilename , 0 ) ;
	if( ibma_config_space->index_space.shm.shmkey == -1 )
	{
		ERRORLOGSG( "ftok[%s][%d] failed , errno[%d]" , ibma_config_space->ibma_conf_pathfilename , ibma_config_space->index_space.shm.proj_id );
		free( ibma_config_space );
		return NULL;
	}
	else
	{
		DEBUGLOGSG( "ftok[%s][%d] ok[0x%X]" , ibma_config_space->ibma_conf_pathfilename , ibma_config_space->index_space.shm.proj_id , ibma_config_space->index_space.shm.shmkey );
	}
	
	ibma_config_space->index_space.shm.shmid = shmget( ibma_config_space->index_space.shm.shmkey , 1 , 0644 ) ;
	if( ibma_config_space->index_space.shm.shmid == -1 )
	{
		ERRORLOGSG( "shmget[0x%X] failed , errno[%d]" , ibma_config_space->index_space.shm.shmkey , errno );
		free( ibma_config_space );
		return NULL;
	}
	else
	{
		DEBUGLOGSG( "shmget[0x%X] ok , shmid[%d]" , ibma_config_space->index_space.shm.shmkey , ibma_config_space->index_space.shm.shmid );
	}
	
	ibma_config_space->index_space.shm.base = shmat( ibma_config_space->index_space.shm.shmid , NULL , 0 ) ;
	if( ibma_config_space->index_space.shm.base == NULL )
	{
		ERRORLOGSG( "shmat[%d] failed , errno[%d]" , ibma_config_space->index_space.shm.shmid , errno );
		free( ibma_config_space );
		return NULL;
	}
	else
	{
		DEBUGLOGSG( "shmat[%d] ok" , ibma_config_space->index_space.shm.shmid );
	}
	
	LocateIndexSpaceAddress( ibma_config_space->index_space.shm.base , & (ibma_config_space->index_space.index_space_attaching) );
	
	open_config_space_error_flag = 0 ;
	
_RETRY_OPEN_CONFIG_SPACE :
	
	ibma_config_space->config_space.shm.shmkey = ibma_config_space->index_space.index_space_attaching->shmkey ;
	ibma_config_space->config_space.shm.shmid = shmget( ibma_config_space->config_space.shm.shmkey , 0 , 0644 ) ;
	if( ibma_config_space->config_space.shm.shmid == -1 )
	{
		ERRORLOGSG( "shmget[0x%X] failed , errno[%d]" , ibma_config_space->config_space.shm.shmkey , errno );
		shmdt( ibma_config_space->index_space.shm.base ); ibma_config_space->index_space.shm.base = NULL ;
		free( ibma_config_space );
		if( open_config_space_error_flag == 0 )
		{
			open_config_space_error_flag = 1 ;
			goto _RETRY_OPEN_CONFIG_SPACE;
		}
		return NULL;
	}
	else
	{
		DEBUGLOGSG( "shmget[0x%X] ok , shmid[%d]" , ibma_config_space->config_space.shm.shmkey , ibma_config_space->config_space.shm.shmid );
	}
	
	ibma_config_space->config_space.shm.base = shmat( ibma_config_space->config_space.shm.shmid , NULL , 0 ) ;
	if( ibma_config_space->config_space.shm.base == NULL )
	{
		ERRORLOGSG( "shmat[%d] failed , errno[%d]" , ibma_config_space->config_space.shm.shmid , errno );
		shmdt( ibma_config_space->index_space.shm.base ); ibma_config_space->index_space.shm.base = NULL ;
		free( ibma_config_space );
		if( open_config_space_error_flag == 0 )
		{
			open_config_space_error_flag = 1 ;
			goto _RETRY_OPEN_CONFIG_SPACE;
		}
		return NULL;
	}
	else
	{
		DEBUGLOGSG( "shmat[%d] ok" , ibma_config_space->config_space.shm.shmid );
	}
	
	LocateConfigSpaceAddress( ibma_config_space->config_space.shm.base , & (ibma_config_space->config_space.config_space_attaching) , & (ibma_config_space->config_space.config_space_addresses) );
	
	return ibma_config_space;
}

int IBMACheckConfigSpaceAttaching( struct IbmaConfigSpace *ibma_config_space )
{
	INFOLOGSG( "ibma_api v%s build %s %s ( ibidl v%s, ibutil v%s )" , g_ibp_ibma_api_kernel_version , __DATE__ , __TIME__ , g_ibp_idl_kernel_version , g_ibp_util_kernel_version );
	
	if( ibma_config_space->index_space.index_space_attaching->shmkey != ibma_config_space->config_space.shm.shmkey )
	{
		shmdt( ibma_config_space->config_space.shm.base );
		INFOLOGSG( "shmdt[%d] ok" , ibma_config_space->config_space.shm.shmid );
		
		memset( & (ibma_config_space->config_space) , 0x00 , sizeof(struct ConfigSpace) );
		
		ibma_config_space->config_space.shm.shmkey = ibma_config_space->index_space.index_space_attaching->shmkey ;
		ibma_config_space->config_space.shm.shmid = shmget( ibma_config_space->config_space.shm.shmkey , 0 , 0644 ) ;
		if( ibma_config_space->config_space.shm.shmid == -1 )
		{
			ERRORLOGSG( "shmget[0x%X] failed , errno[%d]" , ibma_config_space->config_space.shm.shmkey , errno );
			return IBP_IBMA_ERROR_SHMGET_CONFIGSPACE;
		}
		else
		{
			INFOLOGSG( "shmget[0x%X] ok , shmid[%d]" , ibma_config_space->config_space.shm.shmkey , ibma_config_space->config_space.shm.shmid );
		}
		
		ibma_config_space->config_space.shm.base = shmat( ibma_config_space->config_space.shm.shmid , NULL , 0 ) ;
		if( ibma_config_space->config_space.shm.base == NULL )
		{
			ERRORLOGSG( "shmat[%d] failed , errno[%d]" , ibma_config_space->config_space.shm.shmid , errno );
			return IBP_IBMA_ERROR_SHMAT_CONFIGSPACE;
		}
		else
		{
			INFOLOGSG( "shmat[%d] ok" , ibma_config_space->config_space.shm.shmid );
		}
		
		LocateConfigSpaceAddress( ibma_config_space->config_space.shm.base , & (ibma_config_space->config_space.config_space_attaching) , & (ibma_config_space->config_space.config_space_addresses) );
		
		return 1;
	}
	
	return 0;
}

void IBMACloseConfigSpace( struct IbmaConfigSpace *ibma_config_space )
{
	if( ibma_config_space )
	{
		if( ibma_config_space->config_space.shm.base )
		{
			shmdt( ibma_config_space->config_space.shm.base );
			INFOLOGSG( "shmdt[%d] ok" , ibma_config_space->config_space.shm.shmid );
		}
		
		if( ibma_config_space->index_space.shm.base )
		{
			shmdt( ibma_config_space->index_space.shm.base );
			INFOLOGSG( "shmdt[%d] ok" , ibma_config_space->index_space.shm.shmid );
		}
		
		free( ibma_config_space );
	}
	
	return;
}

int IBMAGetRetryConnectTimeval( struct IbmaConfigSpace *ibma_config_space )
{
	return ibma_config_space->index_space.index_space_attaching->retry_connect_timeval;
}

int IBMAGetNodeCount( struct IbmaConfigSpace *ibma_config_space )
{
	return ibma_config_space->config_space.config_space_attaching->nodes_hash_size/4;
}

char *IBMAGetThisNodePtr( struct IbmaConfigSpace *ibma_config_space )
{
	return ibma_config_space->index_space.index_space_attaching->node;
}

struct NodeSpaceUnit *IBMAGetThisNode( struct IbmaConfigSpace *ibma_config_space )
{
	return IBMAQueryNode( ibma_config_space , ibma_config_space->index_space.index_space_attaching->node );
}

struct NodeSpaceUnit *IBMATravelNodes( struct IbmaConfigSpace *ibma_config_space , struct NodeSpaceUnit *p_node_unit )
{
	return TravelNodes( & (ibma_config_space->config_space.config_space_addresses) , p_node_unit );
}

struct NodeSpaceUnit *IBMAQueryNode( struct IbmaConfigSpace *ibma_config_space , char *node )
{
	return QueryNode( ibma_config_space->config_space.config_space_attaching , & (ibma_config_space->config_space.config_space_addresses) , node );
}

char *IBMAGetNodePtr( struct NodeSpaceUnit *p_node_unit )
{
	return GetNodePtr( p_node_unit );
}

char IBMAGetNodeInvalid( struct NodeSpaceUnit *p_node_unit )
{
	return GetNodeInvalid( p_node_unit );
}

int IBMAGetNodeHostCount( struct NodeSpaceUnit *p_node_unit )
{
	return GetNodeHostCount( p_node_unit );
}

char *IBMAGetNodeKey( struct NodeSpaceUnit *p_node_unit , int *p_key_len )
{
	return GetNodeKey( p_node_unit , p_key_len );
}

struct HostSpaceUnit *IBMATravelNodeHosts( struct IbmaConfigSpace *ibma_config_space , struct NodeSpaceUnit *p_node_unit , struct HostSpaceUnit *p_host_unit )
{
	return TravelNodeHosts( & (ibma_config_space->config_space.config_space_addresses) , p_node_unit , p_host_unit );
}

struct HostSpaceUnit *IBMAQueryNodeHost( struct IbmaConfigSpace *ibma_config_space , struct NodeSpaceUnit *p_node_unit , char *ip , int port )
{
	return QueryNodeHost( & (ibma_config_space->config_space.config_space_addresses) , p_node_unit , ip , port );
}

char *IBMAGetHostIpPtr( struct HostSpaceUnit *p_host_unit )
{
	return GetHostIpPtr( p_host_unit );
}

int IBMAGetHostPort( struct HostSpaceUnit *p_host_unit )
{
	return GetHostPort( p_host_unit );
}

int IBMAGetHostLoad( struct HostSpaceUnit *p_host_unit )
{
	return GetHostLoad( p_host_unit );
}

#if 0
char IBMAGetHostInvalid( struct HostSpaceUnit *p_host_unit )
{
	return GetHostInvalid( p_host_unit );
}
#endif

int IBMAGetAppCount( struct IbmaConfigSpace *ibma_config_space )
{
	return ibma_config_space->config_space.config_space_attaching->apps_hash_size/4;
}

struct AppSpaceUnit *IBMATravelApps( struct IbmaConfigSpace *ibma_config_space , struct AppSpaceUnit *p_app_unit )
{
	return TravelApps( & (ibma_config_space->config_space.config_space_addresses) , p_app_unit );
}

struct AppSpaceUnit *IBMAQueryApp( struct IbmaConfigSpace *ibma_config_space , char *app )
{
	return QueryApp( ibma_config_space->config_space.config_space_attaching , & (ibma_config_space->config_space.config_space_addresses) , app );
}

char *IBMAGetAppPtr( struct AppSpaceUnit *p_app_unit )
{
	return GetAppPtr( p_app_unit );
}

char *IBMAGetAppDescPtr( struct AppSpaceUnit *p_app_unit )
{
	return GetAppDescPtr( p_app_unit );
}

char *IBMAGetAppBinPtr( struct AppSpaceUnit *p_app_unit )
{
	return GetAppBinPtr( p_app_unit );
}

int IBMAGetAppTimeout( struct AppSpaceUnit *p_app_unit )
{
	return GetAppTimeout( p_app_unit );
}

int IBMAGetAppTimeout2( struct AppSpaceUnit *p_app_unit )
{
	return GetAppTimeout2( p_app_unit );
}

